#include <iomanip>
#include <cstdlib>
#include <cmath>
#include <strstream>
#include <string>
#include <vector>

using namespace std;
#include "GL/glut.h"

#include "demDataLoad.h"

typedef uint16_t WORD;

Dem_Area::Dem_Area(std::string file_name, int skipx, int skipy)//构造函数
{
	this->_skipx = skipx;
	this->_skipy = skipy;

	ostrstream theheadfile;

	theheadfile<<file_name.substr(0, file_name.find_last_of(".DEM")-3)<<".HDR"<<ends;

	string dem_head(theheadfile.str());

	this->findem.open(file_name.c_str(), ios_base::binary|ios_base::in);

	this->finhead.open(dem_head.c_str(), ios_base::in);

	if(this->findem.fail())
	{
		//MessageBox(NULL, "fail find the dem file", "wrong", MB_OK);
		return;
	}

	if(this->finhead.fail())
	{
		//MessageBox(NULL, "fail find the dem head file", "wrong", MB_OK);
		return;
	}

	this->areainfor = new AreaInf;

	this->get_area_infor();	

	this->_ysimpleCount = areainfor->over_lat/this->_skipy;
	this->_xsimpleCount = areainfor->over_long/this->_skipx;

	if(this->_ysimpleCount<2 || this->_xsimpleCount<2)
		return;
}

Dem_Area::Dem_Area(std::string file_name, int width, int height, int)	
{
	cout<<"Dem_Area::Dem_Area(std::string file_name, int width, int height, int)"<<endl;
	ostrstream theheadfile;

	theheadfile<<file_name.substr(0, file_name.find_last_of(".DEM")-3)<<".HDR"<<ends;

	string dem_head(theheadfile.str());

	this->findem.open(file_name.c_str(), ios_base::binary|ios_base::in);

	this->finhead.open(dem_head.c_str(), ios_base::in);

	if(this->findem.fail())
	{
		//MessageBox(NULL, "fail find the dem file", "wrong", MB_OK);
		return;
	}

	if(this->finhead.fail())
	{
		//MessageBox(NULL, "fail find the dem head file", "wrong", MB_OK);
		return;
	}

	this->areainfor = new AreaInf;

	this->get_area_infor();	

	char* headbytes = new char[this->areainfor->over_long * 2];	

	this->_dem_data_origin_blob = new unsigned char[this->areainfor->over_lat*this->areainfor->over_long*2];

	long loadCount=0;
	//unsigned short theword,my_word;

	for(int row=0; row<this->areainfor->over_lat; ++row)
	{
		findem.read(headbytes, this->areainfor->over_long * 2);	

		for(int col=0; col<this->areainfor->over_long; ++col)
		{
			this->_dem_data_origin_blob[loadCount++] = headbytes[2*col];
			this->_dem_data_origin_blob[loadCount++] =headbytes[2*col+1];
		}
	}

	this->_xsimpleCount = width;
	this->_ysimpleCount = height;
}

Dem_Area::~Dem_Area()
{	
	cout<<endl<<"in Dem_Area destory function"<<endl;
	delete [] this->_dem_data_blob;
	delete [] this->_dem_data_origin_blob;
}

unsigned char* Dem_Area::load_dem_file_avr(unsigned int lenx, unsigned int leny)
{
	cout<<endl<<"in function load_dem_file_avr "<<lenx<<"*"<<leny<<endl;

	if(lenx > (unsigned int)this->_xsimpleCount)
		return NULL;
	if(leny > (unsigned int)this->_ysimpleCount)
		return NULL;

	unsigned char* dataBlobToReturn = new unsigned char[lenx*leny*4];

	//xrate表示在x方向一个插值后的grid覆盖原来的grid的个数
	float xrate = float(this->areainfor->over_long/lenx);
	//yrate表示在y方向一个插值后的grid覆盖原来的grid的个数
	float yrate = float(this->areainfor->over_lat/leny);

	//xpos表示某个插值后的grid的左上角的归一化x位置
	float xpos;
	//ypos表示某个插值后的grid的左上角的归一化y位置
	float ypos;

	//xposOriIntFloat表示某个插值后的grid的左上角x位置映射到原始的grid后的x位置
	float xposOriIntFloat;
	//yposOriIntFloat表示某个插值后的grid的左上角x位置映射到原始的grid后的y位置
	float yposOriIntFloat;

	//xposOriInt表示某个插值后的grid的左上角x位置映射到原始的grid后所在的网格x下标
	int xposOriInt;
	//yposOriInt表示某个插值后的grid的左上角x位置映射到原始的grid后所在的网格y下标
	int yposOriInt;

	//原始的grid一行数据所占的内存的长度
	int collen = this->areainfor->over_long*2;

	float* avr_data = (float*)dataBlobToReturn;

	long assCount = 0;

	float tmpSumValue;
	float tmpSumRate;
	float tmpXownRate;
	float tmpYownRate;

	unsigned short my_word, theword;

	short int tmpWatch;

	cout<<endl<<"before data loading "<<endl;
	for(unsigned int row=0; row<leny; ++row)
	{
		if(row%100==0)
		{
			cout<<endl<<"data loading "<< 100.0f*float(row)/float(this->_ysimpleCount)<<"%";
		}

		ypos = float(row)/float(leny);		

		for(unsigned int col=0; col<lenx; ++col)
		{
			xpos = float(col)/float(lenx);

			xposOriIntFloat = xpos*this->areainfor->over_long;
			yposOriIntFloat = ypos*this->areainfor->over_lat;

			xposOriInt = int(xposOriIntFloat);
			yposOriInt = int(yposOriIntFloat);

			tmpSumRate = 0.0f;
			tmpSumValue = 0.0f;

			do
			{
				if(float(yposOriInt) > yposOriIntFloat)
				{
					if(float(yposOriInt+1) > (yposOriIntFloat+yrate) )
					{							
						tmpYownRate = yposOriIntFloat+yrate - float(yposOriInt);
					}
					else
					{
						tmpYownRate = 1.0f;
					}
				}
				else
				{
					if(float(yposOriInt+1) > (yposOriIntFloat+yrate) )
					{
						tmpYownRate = yrate;
					}
					else
					{
						tmpYownRate = float(yposOriInt+1)-yposOriIntFloat;
					}						
				}

				xposOriInt = int(xposOriIntFloat);

				do
				{
					if(float(xposOriInt) > xposOriIntFloat)
					{
						if(float(xposOriInt+1) > (xposOriIntFloat+xrate) )
						{							
							tmpXownRate = xposOriIntFloat+xrate - float(xposOriInt);
						}
						else
						{
							tmpXownRate = 1.0f;
						}
					}
					else
					{
						if(float(xposOriInt+1) > (xposOriIntFloat+xrate) )
						{
							tmpXownRate = xrate;
						}
						else
						{
							tmpXownRate = float(xposOriInt+1)-xposOriIntFloat;
						}						
					}

					tmpSumRate += tmpXownRate*tmpYownRate;

					my_word = this->_dem_data_origin_blob[2*xposOriInt+yposOriInt*collen];
					my_word <<= 8;			
					theword = this->_dem_data_origin_blob[2*xposOriInt+1+yposOriInt*collen];
					theword &= 0xff;
					my_word += theword;	

					tmpWatch = (short int)(my_word);

					tmpWatch = tmpWatch< -500 ? 0 : tmpWatch;

					tmpSumValue += tmpXownRate*tmpYownRate*float(tmpWatch);

				}while(float(++xposOriInt)<(xposOriIntFloat+xrate));

			}while(float(++yposOriInt)<(yposOriIntFloat+yrate));

			avr_data[assCount++] = tmpSumValue/tmpSumRate;//<500.0f ? (-0.02f):(tmpSumValue/tmpSumRate/9000.0);
		}
	}

	return dataBlobToReturn;
}

//--------------------------------------------------------------------------------
bool Dem_Area::load_dem_file_avr()
{
	cout<<endl<<"in function load_dem_file_avr"<<endl;

	cout<<endl<<"in function load_dem_file_avr"<<(this->_xsimpleCount*this->_ysimpleCount*4)<<endl;
	
	this->_dem_data_blob = new unsigned char[this->_xsimpleCount*this->_ysimpleCount*4];

	//xrate表示在x方向一个插值后的grid覆盖原来的grid的个数
	float xrate = float(this->areainfor->over_long)/float(this->_xsimpleCount);
	//yrate表示在y方向一个插值后的grid覆盖原来的grid的个数
	float yrate = float(this->areainfor->over_lat)/float(this->_ysimpleCount);

	//xpos表示某个插值后的grid的左上角的归一化x位置
	float xpos;
	//ypos表示某个插值后的grid的左上角的归一化y位置
	float ypos;

	//xposOriIntFloat表示某个插值后的grid的左上角x位置映射到原始的grid后的x位置
	float xposOriIntFloat;
	//yposOriIntFloat表示某个插值后的grid的左上角x位置映射到原始的grid后的y位置
	float yposOriIntFloat;

	//xposOriInt表示某个插值后的grid的左上角x位置映射到原始的grid后所在的网格x下标
	int xposOriInt;
	//yposOriInt表示某个插值后的grid的左上角x位置映射到原始的grid后所在的网格y下标
	int yposOriInt;

	//原始的grid一行数据所占的内存的长度
	int collen = this->areainfor->over_long*2;

	float* avr_data = (float*)this->_dem_data_blob;

	long assCount = 0;

	float tmpSumValue;
	float tmpSumRate;
    float tmpXownRate;
	float tmpYownRate;

	unsigned short my_word, theword;

	short int tmpWatch;

	for(int row=0; row<this->_ysimpleCount; ++row)
	{
		if(row%100==0)
		{
			cout<<endl<<"data loading "<< 100.0f*float(row)/float(this->_ysimpleCount)<<"%";
		}

		ypos = float(row)/float(this->_ysimpleCount);		

		for(int col=0; col<this->_xsimpleCount; ++col)
		{
			xpos = float(col)/float(this->_xsimpleCount);

			xposOriIntFloat = xpos*this->areainfor->over_long;
			yposOriIntFloat = ypos*this->areainfor->over_lat;

			xposOriInt = int(xposOriIntFloat);
			yposOriInt = int(yposOriIntFloat);

			tmpSumRate = 0.0f;
			tmpSumValue = 0.0f;

			do
			{
				if(float(yposOriInt) > yposOriIntFloat)
				{
					if(float(yposOriInt+1) > (yposOriIntFloat+yrate) )
					{							
						tmpYownRate = yposOriIntFloat+yrate - float(yposOriInt);
					}
					else
					{
						tmpYownRate = 1.0f;
					}
				}
				else
				{
					if(float(yposOriInt+1) > (yposOriIntFloat+yrate) )
					{
						tmpYownRate = yrate;
					}
					else
					{
						tmpYownRate = float(yposOriInt+1)-yposOriIntFloat;
					}						
				}

				xposOriInt = int(xposOriIntFloat);

				do
				{
					if(float(xposOriInt) > xposOriIntFloat)
					{
						if(float(xposOriInt+1) > (xposOriIntFloat+xrate) )
						{							
							tmpXownRate = xposOriIntFloat+xrate - float(xposOriInt);
						}
						else
						{
							tmpXownRate = 1.0f;
						}
					}
					else
					{
						if(float(xposOriInt+1) > (xposOriIntFloat+xrate) )
						{
							tmpXownRate = xrate;
						}
						else
						{
							tmpXownRate = float(xposOriInt+1)-xposOriIntFloat;
						}						
					}

					tmpSumRate += tmpXownRate*tmpYownRate;

					my_word = this->_dem_data_origin_blob[2*xposOriInt+yposOriInt*collen];
					my_word <<= 8;			
					theword = this->_dem_data_origin_blob[2*xposOriInt+1+yposOriInt*collen];
					theword &= 0xff;
					my_word += theword;	

					tmpWatch = (short int)(my_word);

					tmpWatch = tmpWatch< -500 ? 0 : tmpWatch;

					tmpSumValue += tmpXownRate*tmpYownRate*float(tmpWatch);

				}while(float(++xposOriInt)<(xposOriIntFloat+xrate));

			}while(float(++yposOriInt)<(yposOriIntFloat+yrate));

			avr_data[assCount++] = tmpSumValue/tmpSumRate;//<500.0f ? (-0.02f):(tmpSumValue/tmpSumRate/9000.0);
		}
	}

	return true;
}

bool Dem_Area::load_dem_file()
{
	cout<<endl<<"in function load_dem_file"<<endl;

	char* headbytes = new char[this->areainfor->over_long * 2];	

	WORD theword,my_word;

	long buffersize = areainfor->over_lat * areainfor->over_long/(_skipx*_skipy);
	
	cout<<endl<<"buffer size: "<<areainfor->over_lat<<" * "<<areainfor->over_long
		<<" / ("<<_skipx<<" * "<<_skipy<<")"<<" = "<<buffersize<<endl;

	this->_dem_data_blob = new unsigned char [buffersize*2];

	//从dem文件中读取高度数据，存入数组 _dem_data_blob
	long thecount = 0;	

	for(int row = 0; row<this->areainfor->over_lat; row += this->_skipy)    
	{
		//cout<<row<<"-";

		findem.read(headbytes, this->areainfor->over_long * 2);		

		for(int colum = 0; colum<this->areainfor->over_long; colum += this->_skipx)    
		{
			my_word = headbytes[2*colum];
			my_word <<= 8;			
			theword = headbytes[2*colum+1];
			theword &= 0xff;
			my_word += theword;		

			this->_dem_data_blob[thecount++] = my_word;
		}

		this->findem.seekg((this->_skipx-1)*areainfor->over_long*2, ios_base::cur);		
	}

	return true;
}

//--------------------------------------------------------------------------------

#define getELE(x,y) (x)+(y)*colsize

void Dem_Area::smooth(float key, int pass)
{
	cout<<endl<<endl<<"do smooth filter";

	int colsize = this->areainfor->over_long/this->_skipx;
	int rowsize = this->areainfor->over_lat/this->_skipy;

	cout<<endl<<"colsize = "<<colsize;
	cout<<endl<<"rowsize = "<<rowsize;

	int col, row;

	for (row = 0;	row < rowsize;	++row)
	{
		for(col = 0;	col < colsize;	++col)
		{
			this->_dem_data_blob[getELE(col, row)] = short(this->_dem_data_blob[getELE(col, row)])<short(-550) ? -1 : this->_dem_data_blob[getELE(col, row)];
		}
	}

	for(int p=0; p<pass; p++)
	{
		cout<<endl<<"filter pass "<<p<<" of "<<pass;

		/* Rows, left to right */
		for(col = 1;	col < colsize;	++col)
		{
			for (row = 0;	row < rowsize;	row++)
			{
				this->_dem_data_blob[getELE(col, row)] = short(this->_dem_data_blob[getELE(col-1, row)]) * (1-key) 
					+ short(this->_dem_data_blob[getELE(col, row)]) * key;				
			}
		}

		cout<<endl<<"\t\t\tRows, left to right";

		/* Rows, right to left*/
		for(col = colsize-2;	col < -1;	col--)
		{
			for (row = 0;	row < rowsize;	row++)
			{
				this->_dem_data_blob[getELE(col, row)]  = short(this->_dem_data_blob[getELE(col+1,row)]) * (1-key) 
					+  short(this->_dem_data_blob[getELE(col,row)]) * key;
			}
		}

		cout<<endl<<"\t\t\tRows, right to left";

			/* Columns, bottom to top */
		for(col = 0;	col < colsize;	col++)
		{
			for (row = 1;	row < rowsize;	row++)
			{
				this->_dem_data_blob[getELE(col, row)]  = short(this->_dem_data_blob[getELE(col,row-1)]) * (1-key) 
					+  short(this->_dem_data_blob[getELE(col,row)]) * key;
			}
		}

		cout<<endl<<"\t\t\tColumns, bottom to top";

			/* Columns, top to bottom */
		for(col = 0;	col < colsize;	col++)
		{
			for (row = rowsize;		row < -1;	row--)
			{
				this->_dem_data_blob[getELE(col, row)]  = short(this->_dem_data_blob[getELE(col,row+1)]) * (1-key) 
					+ short(this->_dem_data_blob[getELE(col,row)]) * key;	
			}
		}

		cout<<endl<<"\t\t\tColumns, bottom to top";
	}
}

//======================================Dem_Area used to load the dem file and form the data in memery
bool Dem_Area::get_area_infor()//获得区域信息
{

	//8位 BYTE，  16位 WORD， 32位 DWORD 

	//WORD loValue = LOWORD(lParam);///取低16位
	//WORD hiValue = HIWORD(lParam);///取高16位

	//BYTE loValue = LOBYTE(wValue);///取低8位
	//BYTE hiValue = HIBYTE(wValue);///取高8位	

	if(this->finhead.fail())
	{
		return false;
	}

	char infline[256]={'\0'};

	this->finhead.getline(infline,256);
	this->finhead.getline(infline,256);
	this->finhead.getline(infline,256);
	int j;
	{
		ostrstream thenumber;
		j=0;
		while(j<256)
		{
			if(infline[j] == '.' || (infline[j]>='0' && infline[j]<='9'))
			{
				thenumber<<infline[j];
			}
			j++;
		}
		thenumber<<ends;
		this->areainfor->over_lat = int(atof(thenumber.str()));

		cout<<endl<<"areainfor->over_lat : "<<this->areainfor->over_lat;
	}

	finhead.getline(infline,256);

	{
		ostrstream thenumber;
		j=0;
		while(j<256)

		{
			if(infline[j] == '.' || (infline[j]>='0' && infline[j]<='9'))
			{
				thenumber<<infline[j];
			}
			j++;
		}
		thenumber<<ends;
		this->areainfor->over_long = int(atof(thenumber.str()));

		cout<<endl<<"areainfor->over_long : "<<this->areainfor->over_long;
	}

	this->finhead.getline(infline,256);
	this->finhead.getline(infline,256);
	this->finhead.getline(infline,256);	
	this->finhead.getline(infline,256);
	this->finhead.getline(infline,256);
	this->finhead.getline(infline,256);
	this->finhead.getline(infline,256);

	{
		ostrstream thenumber;
		j=0;
		while(j<256)

		{
			if(infline[j] == '.' || (infline[j]>='0' && infline[j]<='9'))
			{
				thenumber<<infline[j];
			}
			j++;
		}
		thenumber<<ends;
		this->areainfor->start_longitude =atof(thenumber.str());

		cout<<endl<<"areainfor->start_longitude : "<<this->areainfor->start_longitude;
	}

	finhead.getline(infline,256);

	{
		ostrstream thenumber;
		j=0;
		while(j<256)
		{
			if(infline[j] == '.' || (infline[j]>='0' && infline[j]<='9'))
			{
				thenumber<<infline[j];
			}
			j++;
		}
		thenumber<<ends;
		this->areainfor->start_latitude = atof(thenumber.str());

		cout<<endl<<"areainfor->start_latitude : "<<this->areainfor->start_latitude;
	}

	return true; 
}
